home *** CD-ROM | disk | FTP | other *** search
/ The CICA Windows Explosion! / The CICA Windows Explosion! - Disc 2.iso / programr / toolhelp.zip / TEST.C < prev    next >
C/C++ Source or Header  |  1991-05-09  |  52KB  |  1,780 lines

  1. /**************************************************************************
  2.  *  TEST.C
  3.  *
  4.  *      Tests TOOLHELP.DLL
  5.  *
  6.  **************************************************************************/
  7.  
  8. #include <stdio.h>
  9. #undef NULL
  10. #include <windows.h>
  11. #include <string.h>
  12. #include "toolhelp.h"
  13. #include "test.h"
  14.  
  15. /* ----- Symbols ----- */
  16. #define LIST_WIDTH      60
  17. #define LIST_NONE       0
  18. #define LIST_GLOBAL     1
  19. #define LIST_MODULE     2
  20. #define LIST_TASK       3
  21. #define LIST_USER       4
  22. #define LIST_GDI        5
  23. #define LIST_TOOLHELP   6
  24. #define LIST_MEMMAN     7
  25. #define LIST_CLASS      8
  26. #define BUTTON_WIDTH    (10 * xChar)
  27. #define BUTTON_MARGIN   xChar
  28. #define IDM_WRITE       100
  29. #define IDM_WRITEBP     101
  30. #ifndef SHORT
  31. typedef short int SHORT;
  32. #endif
  33.  
  34. /* ----- Memory window extra values ----- */
  35. #define MEM_BLOCK       0
  36. #define MEM_GLOBALENTRY 2
  37. #define MEM_LPOURBLOCK  4
  38. #define MEM_HOURBLOCK   8
  39.  
  40. /* ----- Macros ----- */
  41. #define MAXLINES(dwSize,yClient) \
  42.     max((SHORT)(dwSize / 16) - ((SHORT)yClient) / yChar, 0)
  43.  
  44. /* ----- Function prototypes ----- */
  45.  
  46.     LONG FAR PASCAL WndProc(
  47.         HWND hWnd,
  48.         int iMessage,
  49.         WORD wParam,
  50.         LONG lParam);
  51.  
  52.     LONG FAR PASCAL MemWndProc(
  53.         HWND hWnd,
  54.         int iMessage,
  55.         WORD wParam,
  56.         LONG lParam);
  57.  
  58.     void PASCAL DumpMem(
  59.         HWND hwnd,
  60.         HDC hDC,
  61.         SHORT nScrollPos,
  62.         SHORT nPos);
  63.  
  64.     LONG WalkGlobalHeap(
  65.         HWND hwnd);
  66.  
  67.     LONG WalkFreeList(
  68.         HWND hwnd);
  69.  
  70.     LONG WalkLRUList(
  71.         HWND hwnd);
  72.  
  73.     LONG WalkLocalHeap(
  74.         HWND hwnd,
  75.         HANDLE hBlock);
  76.  
  77.     LONG WalkModuleList(
  78.         HWND hwnd);
  79.  
  80.     LONG WalkTaskList(
  81.         HWND hwnd);
  82.  
  83.     LONG WalkClassList(
  84.         HWND hwnd);
  85.  
  86.     LONG DoStackTrace(
  87.         HWND hwnd);
  88.  
  89.     LONG DoUserInfo(
  90.         HWND hwnd);
  91.  
  92.     LONG DoGDIInfo(
  93.         HWND hwnd);
  94.  
  95.     LONG DoMemManInfo(
  96.         HWND hwnd);
  97.  
  98.     LONG DoGlobalEntryModuleTest(
  99.         HWND hwnd);
  100.  
  101.     LONG ReadMemoryTest(
  102.         HWND hwnd,
  103.         HANDLE hBlock);
  104.  
  105.     LONG TimerCountTest(
  106.         HWND hwnd);
  107.  
  108.     BOOL FAR PASCAL MyNotifyHandler(
  109.         WORD wID,
  110.         DWORD dwData);
  111.  
  112.     WORD _cdecl MyCFaultHandler(
  113.         WORD wES,
  114.         WORD wDS,
  115.         WORD wDI,
  116.         WORD wSI,
  117.         WORD wBP,
  118.         WORD wSP,
  119.         WORD wBX,
  120.         WORD wDX,
  121.         WORD wCX,
  122.         WORD wOldAX,
  123.         WORD wOldBP,
  124.         WORD wRetIP,
  125.         WORD wRetCS,
  126.         WORD wRealAX,
  127.         WORD wNumber,
  128.         WORD wHandle,
  129.         WORD wIP,
  130.         WORD wCS,
  131.         WORD wFlags);
  132.  
  133.     BOOL FAR PASCAL FaultDialogProc(
  134.         HWND hDlg,
  135.         WORD wMessage,
  136.         WORD wParam,
  137.         DWORD dwParam);
  138.  
  139. /* ----- Global variables ----- */
  140.     short xScreen;
  141.     short yScreen;
  142.     short xChar;
  143.     short yChar;
  144.     HANDLE hInst;
  145.     HWND hwndList;
  146.     HWND hwndListLocal;
  147.     HWND hwndListStatic;
  148.     WORD wListStatus = LIST_NONE;
  149.     char szText[80];
  150.     HWND hwndMain;
  151.     WORD wNotifyIn;
  152.     WORD wNotifyOut;
  153.     WORD wNotifyState;
  154.     WORD wFilterState;
  155.     WORD wsCS;
  156.     WORD wsIP;
  157.     WORD wsFault;
  158.     WORD wsFaultTask;
  159.     WORD wsProgramTask;
  160.     char szAppName[] = "THTest";
  161.     char szMemName[] = "THMemPopup";
  162.     extern BYTE _AHINCR;
  163.  
  164.     char *szBlockTypes[] =
  165.     {
  166.         "Private", "DGroup", "Data", "Code", "Task", "Resource",
  167.         "Module", "Free", "Internal", "Sentinel", "BMaster"
  168.     };
  169.     char bHasData[] =
  170.     { 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0 };
  171.     char *szLocalFlags[] =
  172.     { "", "Fixed", "Free", "", "Moveable" };
  173.     char *szGDI[] =
  174.     {
  175.         "Unknown", "Pen", "Brush", "Font", "Palette", "Bitmap", "Region",
  176.         "DC", "DisabledDC", "MetaDC", "Metafile", ""
  177.     };
  178.     char *szUser[] =
  179.     {
  180.         "Unknown", "Class", "Window", "String", "Menu", "Clip", "CBox",
  181.         "Palette", "Ed", "Bwl", "OwnerDraw", "SPB", "CheckPoint", "DCE",
  182.         "MWP", "PROP", "LBIV", "Misc", "Atoms", "LockInp", "HookList",
  183.         "UserSeeUserDo", "HotKeyList", "PopupMenu", "HandleTab", ""
  184.     };
  185.     char *szNotify[] =
  186.     {
  187.         "Unknown", "LoadSeg", "FreeSeg", "StartTask", "ExitTask",
  188.         "LoadDLL", "DelModule", "DebugStr", "RIP", "TaskIn",
  189.         "TaskOut", "InChar", "OutStr", "CASRq"
  190.     };
  191.  
  192.  
  193. /*  WinMain
  194.  */
  195.  
  196. int PASCAL WinMain(
  197.     HANDLE hInstance,
  198.     HANDLE hPrevInstance,
  199.     LPSTR lpszCmdLine,
  200.     int nCmdShow)
  201. {
  202.     HWND hwnd;
  203.     MSG msg;
  204.     WNDCLASS wndclass;
  205.     FARPROC lpfnNotify;
  206.     FARPROC lpfnFault;
  207.  
  208.     /* Register the interrupt handler */
  209.     wsProgramTask = GetCurrentTask();
  210.     lpfnFault = MakeProcInstance(MyFaultHandler, hInstance);
  211.     if (!InterruptRegister(NULL, lpfnFault))
  212.     {
  213.         OutputDebugString("THTest: Interrupt hook failed!!\r\n");
  214.         return 1;
  215.     }
  216.  
  217.     /* Register the notification handler */
  218.     lpfnNotify = MakeProcInstance(MyNotifyHandler, hInstance);
  219.     if (!NotifyRegister(
  220.         NULL, lpfnNotify, NF_TASKSWITCH | NF_RIP | NF_DEBUGSTR))
  221.     {
  222.         OutputDebugString("THTest: Notification hook failed!!\r\n");
  223.         return 1;
  224.     }
  225.  
  226.     xScreen = GetSystemMetrics(SM_CXSCREEN);
  227.     yScreen = GetSystemMetrics(SM_CYSCREEN);
  228.     hInst = hInstance;
  229.  
  230.     if (!hPrevInstance)
  231.     {
  232.         wndclass.style = 0L;
  233.         wndclass.lpfnWndProc = WndProc;
  234.         wndclass.cbClsExtra = 0;
  235.         wndclass.cbWndExtra = 0;
  236.         wndclass.hInstance = hInstance;
  237.         wndclass.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(1));
  238.         wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
  239.         wndclass.hbrBackground = (HBRUSH) (COLOR_WINDOW + 1);
  240.         wndclass.lpszMenuName = MAKEINTRESOURCE(ID_MENU);
  241.         wndclass.lpszClassName = szAppName;
  242.  
  243.         if (!RegisterClass(&wndclass))
  244.             return FALSE;
  245.  
  246.         wndclass.style = 0L;
  247.         wndclass.lpfnWndProc = MemWndProc;
  248.         wndclass.cbClsExtra = 0;
  249.         wndclass.cbWndExtra = 10;
  250.         wndclass.hInstance = hInstance;
  251.         wndclass.hIcon = NULL;
  252.         wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
  253.         wndclass.hbrBackground = (HBRUSH) (COLOR_WINDOW + 1);
  254.         wndclass.lpszMenuName = NULL;
  255.         wndclass.lpszClassName = szMemName;
  256.  
  257.         if (!RegisterClass(&wndclass))
  258.             return FALSE;
  259.     }
  260.  
  261.     hwnd = CreateWindow(
  262.         szAppName,              /* Window class name */
  263.         "TOOLHELP.DLL Test",    /* Window caption */
  264.         WS_OVERLAPPEDWINDOW,    /* Window style */
  265.         CW_USEDEFAULT,          /* Initial X position */
  266.         0,                      /* Initial Y position */
  267.         CW_USEDEFAULT,          /* Initial X size */
  268.         0,                      /* Initial Y size */
  269.         NULL,                   /* Parent window handle */
  270.         NULL,                   /* Window menu handle */
  271.         hInstance,              /* Program instance handle */
  272.         NULL);                  /* Create parameters */
  273.  
  274.     ShowWindow(hwnd, nCmdShow);
  275.     UpdateWindow(hwnd);
  276.  
  277.     hwndMain = hwnd;
  278.  
  279.     while (GetMessage(&msg, NULL, 0, 0))
  280.     {
  281.         TranslateMessage(&msg);
  282.         DispatchMessage(&msg);
  283.     }
  284.  
  285.     /* Get rid of our Fault handler and our notification handler */
  286.     InterruptUnRegister(NULL);
  287.     FreeProcInstance(lpfnFault);
  288.     NotifyUnRegister(NULL);
  289.     FreeProcInstance(lpfnNotify);
  290.  
  291.     return msg.wParam;
  292. }
  293.  
  294.  
  295. LONG FAR PASCAL WndProc(
  296.     HWND hwnd,
  297.     int nMessage,
  298.     WORD wParam,
  299.     LONG lParam)
  300. {
  301.     HDC hDC;
  302.     TEXTMETRIC tm;
  303.     WORD wLine;
  304.     HANDLE hTask;
  305.     static HFONT hFont;
  306.  
  307.     switch (nMessage)
  308.     {
  309.     case WM_CREATE:
  310.  
  311.         /* Get static constants */
  312.         hDC = GetDC(hwnd);
  313.         GetTextMetrics(hDC, &tm);
  314.         xChar = tm.tmAveCharWidth;
  315.         yChar = tm.tmHeight + tm.tmExternalLeading;
  316.         ReleaseDC(hwnd, hDC);
  317.  
  318.         /* Create child controls */
  319.         hwndListStatic = CreateWindow(
  320.             "static",
  321.             NULL,
  322.             WS_CHILD | WS_VISIBLE | SS_LEFT,
  323.             xChar, 4 * yChar, 0, 0,
  324.             hwnd, 1, hInst, NULL);
  325.         hwndList = CreateWindow(
  326.             "listbox",
  327.             NULL,
  328.             WS_CHILD | WS_VISIBLE | WS_BORDER | WS_VSCROLL | LBS_USETABSTOPS |
  329.             LBS_NOTIFY,
  330.             xChar, 5 * yChar + 2, 0, 0,
  331.             hwnd, 2, hInst, NULL);
  332.         hwndListLocal = CreateWindow(
  333.             "listbox",
  334.             NULL,
  335.             WS_CHILD | WS_VISIBLE | WS_BORDER | WS_VSCROLL | LBS_USETABSTOPS |
  336.             LBS_NOTIFY,
  337.             xChar, 0, 0, 0,
  338.             hwnd, 3, hInst, NULL);
  339.  
  340.         /* Put a small non-proportional font in the box */
  341.            hFont = GetStockObject(SYSTEM_FIXED_FONT);
  342.         SendMessage(hwndList, WM_SETFONT, hFont, NULL);
  343.         SendMessage(hwndListLocal, WM_SETFONT, hFont, NULL);
  344.         break;
  345.  
  346.     case WM_SIZE:
  347.         if (HIWORD(lParam) < 8 * yChar || LOWORD(lParam) < 10 * xChar)
  348.         {
  349.             ShowWindow(hwndList, SW_HIDE);
  350.             ShowWindow(hwndListLocal, SW_HIDE);
  351.             ShowWindow(hwndListStatic, SW_HIDE);
  352.         }
  353.         else
  354.         {
  355.             short nHeight;
  356.             short nWidth;
  357.  
  358.             nHeight = (HIWORD(lParam) - 2 * yChar) / 2 - yChar / 2;
  359.             nWidth = LOWORD(lParam) - 2 * xChar;
  360.             ShowWindow(hwndList, SW_SHOWNORMAL);
  361.             ShowWindow(hwndListStatic, SW_SHOWNORMAL);
  362.             ShowWindow(hwndListLocal, SW_SHOWNORMAL);
  363.             MoveWindow(hwndList, xChar, yChar, nWidth, nHeight, TRUE);
  364.             MoveWindow(hwndListLocal, xChar, yChar + nHeight + yChar,
  365.                 nWidth, nHeight, TRUE);
  366.             MoveWindow(hwndListStatic, 2 * xChar, 0, nWidth - 2 * xChar,
  367.                 yChar, TRUE);
  368.             UpdateWindow(hwndList);
  369.             UpdateWindow(hwndListLocal);
  370.         }
  371.         return 0L;
  372.  
  373.     case WM_USER:
  374.         wsprintf(szText, "%-12s\t| %08lX",
  375.             (LPSTR)szNotify[wParam], lParam);
  376.         SendMessage(hwndListLocal, LB_ADDSTRING, 0, (LONG)(LPSTR)szText);
  377.         return 0L;
  378.  
  379.     case WM_COMMAND:
  380.         switch (wParam)
  381.         {
  382.         case 2:     /* List box notification message */
  383.             if (HIWORD(lParam) != LBN_DBLCLK)
  384.                 return 0L;
  385.  
  386.             if (wListStatus == LIST_GLOBAL)
  387.             {
  388.                 HANDLE hBlock;
  389.                 GLOBALENTRY Global;
  390.  
  391.                 /* Get the global handle from the list box */
  392.                 SendMessage(hwndList, LB_GETTEXT,
  393.                     (WORD)SendMessage(hwndList, LB_GETCURSEL, 0, 0L),
  394.                     (LONG)(LPSTR)szText);
  395.                 sscanf(szText, "%*2c%*lx %*2c%x", &hBlock);
  396.  
  397.                 /* See if this block has a local heap, if not, call the
  398.                  *  memory dump routine to test the memory functions.
  399.                  */
  400.                 if (hBlock)
  401.                 {
  402.                     Global.dwSize = sizeof (GLOBALENTRY);
  403.                     GlobalEntryHandle(&Global, hBlock);
  404.                 }
  405.                 if (!hBlock)
  406.                     return 0L;
  407.                 else if (Global.wHeapPresent)
  408.                     return WalkLocalHeap(hwnd, hBlock);
  409.                 else
  410.                     return ReadMemoryTest(hwnd, hBlock);
  411.             }
  412.             else if (wListStatus == LIST_TASK)
  413.                 return DoStackTrace(hwnd);
  414.             else
  415.                 return 0L;
  416.  
  417.         case IDM_TEST_1:
  418.             return WalkGlobalHeap(hwnd);
  419.  
  420.         case IDM_TEST_2:
  421.             return WalkFreeList(hwnd);
  422.  
  423.         case IDM_TEST_3:
  424.             return WalkLRUList(hwnd);
  425.  
  426.         case IDM_TEST_4:
  427.             return WalkModuleList(hwnd);
  428.  
  429.         case IDM_TEST_5:
  430.             return WalkTaskList(hwnd);
  431.  
  432.         case IDM_TEST_10:
  433.             return WalkClassList(hwnd);
  434.  
  435.         case IDM_TEST_6:
  436.             return DoUserInfo(hwnd);
  437.  
  438.         case IDM_TEST_7:
  439.             return DoGDIInfo(hwnd);
  440.  
  441.         case IDM_TEST_8:
  442.             return DoGlobalEntryModuleTest(hwnd);
  443.  
  444.         case IDM_TEST_9:
  445.             return DoMemManInfo(hwnd);
  446.  
  447.         case IDM_TEST_11:
  448.             if (wListStatus != LIST_TASK)
  449.                 return 0L;
  450.  
  451.             /* Get the task handle from the list box */
  452.             SendMessage(hwndList, LB_GETTEXT,
  453.                 (WORD)SendMessage(hwndList, LB_GETCURSEL, 0, 0L),
  454.                 (LONG)(LPSTR)szText);
  455.             sscanf(szText, "%*6c%x", &hTask);
  456.  
  457.             /* Nuke the task if it is not the current one */
  458.             if (hTask != wsProgramTask)
  459.                 TerminateApp(hTask, NO_UAE_BOX);
  460.  
  461.             /* Update the task list and get out */
  462.             return WalkTaskList(hwnd);
  463.  
  464.         case IDM_TEST_12:
  465.             return TimerCountTest(hwnd);
  466.  
  467.         case IDM_EXIT:
  468.             SendMessage(hwnd, WM_CLOSE, 0, 0L);
  469.             break;
  470.  
  471.         case IDM_FAULT_1:
  472.         case IDM_FAULT_2:
  473.         case IDM_FAULT_3:
  474.         case IDM_FAULT_4:
  475.         case IDM_FAULT_5:
  476.         case IDM_FAULT_6:
  477.         case IDM_FAULT_7:
  478.         case IDM_FAULT_8:
  479.             Fault(wParam);
  480.             return 0L;
  481.  
  482.         case IDM_NOTIFY_ENABLE:
  483.             if (GetMenuState(GetMenu(hwnd), IDM_NOTIFY_ENABLE, 0) & MF_CHECKED)
  484.             {
  485.                 wNotifyState = FALSE;
  486.                 CheckMenuItem(GetMenu(hwnd), IDM_NOTIFY_ENABLE, MF_UNCHECKED);
  487.             }
  488.             else
  489.             {
  490.                 wNotifyState = TRUE;
  491.                 CheckMenuItem(GetMenu(hwnd), IDM_NOTIFY_ENABLE, MF_CHECKED);
  492.             }
  493.             return 0L;
  494.  
  495.         case IDM_FILTER_ENABLE:
  496.             if (GetMenuState(GetMenu(hwnd), IDM_FILTER_ENABLE, 0) & MF_CHECKED)
  497.             {
  498.                 wFilterState = FALSE;
  499.                 CheckMenuItem(GetMenu(hwnd), IDM_FILTER_ENABLE, MF_UNCHECKED);
  500.             }
  501.             else
  502.             {
  503.                 wFilterState = TRUE;
  504.                 CheckMenuItem(GetMenu(hwnd), IDM_FILTER_ENABLE, MF_CHECKED);
  505.             }
  506.             return 0L;
  507.  
  508.         case IDM_NOTIFY_CLEAR:
  509.             SendMessage(hwndListLocal, WM_SETREDRAW, FALSE, 0L);
  510.             SendMessage(hwndListLocal, LB_RESETCONTENT, 0, 0L);
  511.             SendMessage(hwndListLocal, WM_SETREDRAW, TRUE, 0L);
  512.             InvalidateRect(hwndListLocal, NULL, TRUE);
  513.             return 0L;
  514.         }
  515.         break;
  516.  
  517.     case WM_DESTROY:
  518.         PostQuitMessage(0);
  519.         break;
  520.  
  521.     default:
  522.         return DefWindowProc(hwnd, nMessage, wParam, lParam);
  523.     }
  524.  
  525.     return 0L;
  526. }
  527.  
  528. /*  MemWndProc
  529.  *      Window proc for memory browser.
  530.  */
  531.  
  532. LONG FAR PASCAL MemWndProc(
  533.     HWND hwnd,
  534.     int nMessage,
  535.     WORD wParam,
  536.     LONG lParam)
  537. {
  538.     CREATESTRUCT *lpCreate;
  539.     GLOBALENTRY *pGlobal;
  540.     WORD w;
  541.     LPSTR lpBlock;
  542.     RECT rect;
  543.     HMENU hMenu;
  544.     DWORD dwReturn;
  545.  
  546.     switch (nMessage)
  547.     {
  548.     case WM_CREATE:
  549.         /* Save the block pointer as window WORD 0 */
  550.         SetWindowWord(hwnd, MEM_BLOCK,
  551.             LOWORD((LONG)((LPCREATESTRUCT)lParam)->lpCreateParams));
  552.  
  553.         /* Get information about this block */
  554.         pGlobal = (GLOBALENTRY *)LocalAlloc(LMEM_FIXED, sizeof (GLOBALENTRY));
  555.         if (!pGlobal)
  556.         {
  557.             PostMessage(hwnd, WM_CLOSE, 0, 0L);
  558.             break;
  559.         }
  560.         pGlobal->dwSize = sizeof (GLOBALENTRY);
  561.         if (!GlobalEntryHandle(pGlobal, GetWindowWord(hwnd, MEM_BLOCK)))
  562.         {
  563.             MessageBox(hwnd, "Block Handle is invalid", "Browser", IDOK);
  564.             PostMessage(hwnd, WM_CLOSE, 0, 0L);
  565.             break;
  566.         }
  567.  
  568.         /* Save GLOBALENTRY pointer as window WORD 2 */
  569.         SetWindowWord(hwnd, MEM_GLOBALENTRY, (WORD)pGlobal);
  570.  
  571.         /* Now read the memory into our global block */
  572.         w = GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT, pGlobal->dwBlockSize);
  573.         if (!w)
  574.         {
  575.             MessageBox(hwnd, "Not enough memory to copy block",
  576.                 "Browser", IDOK);
  577.             PostMessage(hwnd, WM_CLOSE, 0, 0L);
  578.             return 0L;
  579.         }
  580.         lpBlock = GlobalLock(w);
  581.         SetWindowWord(hwnd, MEM_HOURBLOCK, w);
  582.         SetWindowLong(hwnd, MEM_LPOURBLOCK, (LONG)lpBlock);
  583.         MemoryRead(GetWindowWord(hwnd, MEM_BLOCK), 0L, lpBlock,
  584.             pGlobal->dwBlockSize);
  585.  
  586.         /* Put a new item on the system menu to rewrite the block */
  587.         hMenu = GetSystemMenu(hwnd, 0);
  588.         AppendMenu(hMenu, MF_STRING, IDM_WRITE, "&Write");
  589.         AppendMenu(hMenu, MF_STRING, IDM_WRITEBP, "Write &BP");
  590.  
  591.         break;
  592.  
  593.     case WM_SIZE:
  594.     {
  595.         SHORT nScrollMax;
  596.  
  597.         /* Compute the scroll bar maximum and position */
  598.         pGlobal = (GLOBALENTRY *)GetWindowWord(hwnd, MEM_GLOBALENTRY);
  599.         nScrollMax = MAXLINES(pGlobal->dwBlockSize, HIWORD(lParam));
  600.         SetScrollRange(hwnd, SB_VERT, 0, nScrollMax, FALSE);
  601.         SetScrollPos(hwnd, SB_VERT, min(GetScrollPos(hwnd, SB_VERT),
  602.             nScrollMax), FALSE);
  603.  
  604.         /* Force the whole thing to repaint */
  605.         InvalidateRect(hwnd, NULL, TRUE);
  606.         break;
  607.     }
  608.  
  609.     case WM_VSCROLL:
  610.     {
  611.         SHORT nScrollInc;
  612.         SHORT nScrollPos;
  613.         SHORT nScrollMin;
  614.         SHORT nScrollMax;
  615.  
  616.         /* Get the current position */
  617.         nScrollPos = GetScrollPos(hwnd, SB_VERT);
  618.         GetScrollRange(hwnd, SB_VERT, &nScrollMin, &nScrollMax);
  619.         GetClientRect(hwnd, &rect);
  620.  
  621.         /* Decode the various forms of scrolling */
  622.         switch (wParam)
  623.         {
  624.         case SB_TOP:
  625.             nScrollInc = -nScrollPos;
  626.             break;
  627.  
  628.         case SB_BOTTOM:
  629.             nScrollInc = nScrollMax - nScrollPos;
  630.             break;
  631.  
  632.         case SB_LINEUP:
  633.             nScrollInc = -1;
  634.             break;
  635.  
  636.         case SB_LINEDOWN:
  637.             nScrollInc = 1;
  638.             break;
  639.  
  640.         case SB_PAGEUP:
  641.             nScrollInc = min(-1, -rect.bottom / yChar);
  642.             break;
  643.  
  644.         case SB_PAGEDOWN:
  645.             nScrollInc = max(1, rect.bottom / yChar);
  646.             break;
  647.  
  648.         case SB_THUMBTRACK:
  649.             nScrollInc = LOWORD(lParam) - nScrollPos;
  650.             break;
  651.  
  652.         default:
  653.             nScrollInc = 0;
  654.             break;
  655.         }
  656.         
  657.         /* Now do the scroll */
  658.         if (nScrollInc = max(-nScrollPos,
  659.             min(nScrollInc, nScrollMax - nScrollPos)))
  660.         {
  661.             ScrollWindow(hwnd, 0, -yChar * nScrollInc, NULL, NULL);
  662.             SetScrollPos(hwnd, SB_VERT, nScrollPos + nScrollInc, TRUE);
  663.             UpdateWindow(hwnd);
  664.         }
  665.         break;
  666.     }
  667.  
  668.     case WM_PAINT:
  669.     {
  670.         PAINTSTRUCT ps;
  671.         SHORT nScrollMin;
  672.         SHORT nScrollMax;
  673.         SHORT nScrollPos;
  674.         SHORT nStart;
  675.         SHORT nEnd;
  676.         HFONT hFont;
  677.         HFONT hOldFont;
  678.  
  679.         BeginPaint(hwnd, &ps);
  680.  
  681.         /* Compute the number of lines to paint */
  682.         pGlobal = (GLOBALENTRY *)GetWindowWord(hwnd, MEM_GLOBALENTRY);
  683.         nScrollPos = GetScrollPos(hwnd, SB_VERT);
  684.         GetScrollRange(hwnd, SB_VERT, &nScrollMin, &nScrollMax);
  685.         nStart = max(0, nScrollPos + ps.rcPaint.top / yChar - 1);
  686.         nEnd = min((SHORT)(pGlobal->dwBlockSize / 16) + 1,
  687.             nScrollPos + ps.rcPaint.bottom / yChar + 1);
  688.  
  689.         /* Get a font to use */
  690.            hFont = GetStockObject(SYSTEM_FIXED_FONT);
  691.         hOldFont = SelectObject(ps.hdc, hFont);
  692.  
  693.         /* Loop through and draw all lines */
  694.         for (; nStart < nEnd ; ++nStart)
  695.             DumpMem(hwnd, ps.hdc, nScrollPos, nStart);
  696.  
  697.         /* Delete the font that is no longer needed */
  698.         DeleteObject(SelectObject(ps.hdc, hOldFont));
  699.  
  700.         EndPaint(hwnd, &ps);
  701.         break;
  702.     }
  703.  
  704.     case WM_DESTROY:
  705.         /* Free memory associated with this window */
  706.         LocalFree(GetWindowWord(hwnd, MEM_GLOBALENTRY));
  707.         w = GetWindowWord(hwnd, MEM_HOURBLOCK);
  708.         GlobalUnlock(w);
  709.         GlobalFree(w);
  710.         return 0L;
  711.  
  712.     case WM_COMMAND:
  713.         switch (wParam)
  714.         {
  715.         case 1:     /* Close button */
  716.             SendMessage(hwnd, WM_CLOSE, 0, 0L);
  717.             return 0L;
  718.  
  719.         case 2:     /* Write button */
  720.             return 0L;
  721.  
  722.         default:
  723.             return DefWindowProc(hwnd, nMessage, wParam, lParam);
  724.         }
  725.  
  726.     case WM_SYSCOMMAND:
  727.         if (wParam == IDM_WRITE)
  728.         {
  729.             /* Write the block */
  730.             pGlobal = (GLOBALENTRY *)GetWindowWord(hwnd, MEM_GLOBALENTRY);
  731.             lpBlock = (LPSTR)GetWindowLong(hwnd, MEM_LPOURBLOCK);
  732.             dwReturn = MemoryWrite(GetWindowWord(hwnd, MEM_BLOCK),
  733.                 0L, lpBlock, pGlobal->dwBlockSize);
  734.             wsprintf(szText, "%lXh bytes written", dwReturn);
  735.             MessageBox(hwnd, szText, "Memory Browser Write", MB_OK);
  736.             InvalidateRect(hwnd, NULL, TRUE);
  737.             break;
  738.         }
  739.         else if (wParam == IDM_WRITEBP)
  740.         {
  741.             /* Write the breakpoint only if it's code */
  742.             pGlobal = (GLOBALENTRY *)GetWindowWord(hwnd, MEM_GLOBALENTRY);
  743.             if (pGlobal->wType != GT_CODE)
  744.             {
  745.                 MessageBox(hwnd, "Breakpoints only go in code segments",
  746.                     "Memory Browser Breakpoint", MB_OK);
  747.                 return 0L;
  748.             }
  749.             lpBlock = (LPSTR)GetWindowLong(hwnd, MEM_LPOURBLOCK);
  750.             *lpBlock = 0xcc;
  751.             dwReturn = MemoryWrite(GetWindowWord(hwnd, MEM_BLOCK),
  752.                 0L, lpBlock, 1);
  753.             wsprintf(szText, "%lXh bytes written", dwReturn);
  754.             MessageBox(hwnd, szText, "Memory Browser Write", MB_OK);
  755.             InvalidateRect(hwnd, NULL, TRUE);
  756.             break;
  757.         }
  758.         else
  759.             return DefWindowProc(hwnd, nMessage, wParam, lParam);
  760.  
  761.     default:
  762.         return DefWindowProc(hwnd, nMessage, wParam, lParam);
  763.     }
  764.  
  765.     return 0L;
  766. }
  767.  
  768.  
  769. /*  DumpMem
  770.  *      Dumps memory to the memory window.  This routine is called once
  771.  *      per memory line to dump in the middle of the paint message.
  772.  */
  773.  
  774. void PASCAL DumpMem(
  775.     HWND hwnd,
  776.     HDC hDC,
  777.     SHORT nScrollPos,
  778.     SHORT nPos)
  779. {
  780.     LPSTR lpMem;
  781.     DWORD dwOffset;
  782.     WORD i;
  783.     PSTR pstr;
  784.     BYTE by;
  785.     BYTE byCount;
  786.     BYTE byBadCount;
  787.     GLOBALENTRY *pGlobal;
  788.  
  789.     /* Get a pointer to the memory */
  790.     dwOffset = ((DWORD)(WORD)nPos) << 4;
  791.     lpMem = (LPSTR)MAKELONG(LOWORD(dwOffset),
  792.         GetWindowWord(hwnd, MEM_LPOURBLOCK + 2) +
  793.         HIWORD(dwOffset) * (WORD)&_AHINCR);
  794.  
  795.     /* How many real characters are there to draw? */
  796.     pGlobal = (GLOBALENTRY *)GetWindowWord(hwnd, MEM_GLOBALENTRY);
  797.     if (pGlobal->dwBlockSize < dwOffset + 16)
  798.     {
  799.         if (pGlobal->dwBlockSize < dwOffset)
  800.         {
  801.             byCount = 0;
  802.             byBadCount = 16;
  803.         }
  804.         else
  805.         {
  806.             byCount = pGlobal->dwBlockSize - dwOffset;
  807.             byBadCount = 16 - byCount;
  808.         }
  809.     }
  810.     else
  811.     {
  812.         byCount = 16;
  813.         byBadCount = 0;
  814.     }
  815.  
  816.     /* Put into a string so we can see it */
  817.     pstr = szText;
  818.     pstr += wsprintf(pstr, "%06lX:", dwOffset);
  819.     for (i = 0 ; i < byCount ; ++i)
  820.         pstr += wsprintf(pstr, "%02X ",
  821.             (WORD)*(unsigned char FAR *)(lpMem + i));
  822.     for (i = 0 ; i < byBadCount ; ++i)
  823.         pstr += wsprintf(pstr, "?? ");
  824.     for (i = 0 ; i < byCount ; ++i)
  825.     {
  826.         by = *(lpMem + i);
  827.         pstr += wsprintf(pstr, "%c", by >= ' ' ? by : '.');
  828.     }
  829.     for (i = 0 ; i < byBadCount ; ++i)
  830.         pstr += wsprintf(pstr, "?");
  831.  
  832.     /* Draw the text */
  833.     TextOut(hDC, xChar, yChar * (nPos - nScrollPos), szText,
  834.         strlen(szText));
  835. }
  836.  
  837.  
  838. /*  WalkGlobalHeap
  839.  *      Walks the global heap in the list box.  Returns the WndProc return
  840.  *      value.
  841.  */
  842.  
  843. LONG WalkGlobalHeap(
  844.     HWND hwnd)
  845. {
  846.     GLOBALINFO GlobalInf;
  847.     GLOBALENTRY Global;
  848.     MODULEENTRY Module;
  849.     TASKENTRY Task;
  850.     char *npText;
  851.     char *npstr;
  852.     int i;
  853.     HCURSOR hCursor;
  854.  
  855.     /* Turn on the hourglass */
  856.     hCursor = SetCursor(LoadCursor(NULL, IDC_WAIT));
  857.     ShowCursor(TRUE);
  858.     wListStatus = LIST_GLOBAL;
  859.  
  860.     /* Allocate a buffer to store this stuff in.  Pad this number
  861.      *  because the LocalAlloc corrupts the walk.
  862.      */
  863.     GlobalInf.dwSize = sizeof (GLOBALINFO);
  864.     GlobalInfo(&GlobalInf);
  865.     npText = npstr = (char *)LocalAlloc(LMEM_FIXED | LMEM_ZEROINIT,
  866.         (GlobalInf.wcItems + 10) * (LIST_WIDTH + 1));
  867.     if (!npText)
  868.         return 0L;
  869.  
  870.     /* Loop through the global heap */
  871.     Global.dwSize = sizeof (GLOBALENTRY);
  872.     Module.dwSize = sizeof (MODULEENTRY);
  873.     Task.dwSize = sizeof (TASKENTRY);
  874.     if (GlobalFirst(&Global, GLOBAL_ALL))
  875.     {
  876.         char temp[30];
  877.  
  878.         i = 0;
  879.         do
  880.         {
  881.             /* Get the module name */
  882.             if (!Global.hOwner)
  883.                 lstrcpy(Module.szModule, "FREE");
  884.             else if (!ModuleFindHandle(&Module, Global.hOwner))
  885.             {
  886.                 if (TaskFindHandle(&Task, Global.hOwner))
  887.                     lstrcpy(Module.szModule, Task.szModule);
  888.                 else
  889.                     *Module.szModule = '\0';
  890.             }
  891.  
  892.             /* Put some fun garbage in the text buffer */
  893.             if (bHasData[Global.wType])
  894.                 sprintf(temp, "%s %d",
  895.                     szBlockTypes[Global.wType], Global.wData);
  896.             else
  897.                 lstrcpy(temp,szBlockTypes[Global.wType]);
  898.             sprintf(npstr,
  899.                 "A=%08lX h=%04X S=%08lX O=%04X %c %-8s %s",
  900.                 Global.dwAddress, Global.hBlock, Global.dwBlockSize,
  901.                 Global.hOwner,
  902.                 Global.wHeapPresent ? 'Y' : 'N',
  903.                 Module.szModule,
  904.                 temp);
  905.  
  906.             /* Bump to the next spot */
  907.             npstr += LIST_WIDTH + 1;
  908.             ++i;
  909.         }
  910.         while (GlobalNext(&Global, GLOBAL_ALL));
  911.     }
  912.  
  913.     /* Create number of items string */
  914.     sprintf(szText, "GLOBAL_ALL:  Items = %u Really = %u",
  915.         GlobalInf.wcItems, i);
  916.  
  917.     /* Clear list box */
  918.     SendMessage(hwndList, WM_SETREDRAW, FALSE, 0L);
  919.     SendMessage(hwndList, LB_RESETCONTENT, 0, 0L);
  920.  
  921.     /* Loop through all blocks, putting them in list box */
  922.     for (i = 0, npstr = npText ; i < GlobalInf.wcItems ;
  923.         ++i, npstr += LIST_WIDTH + 1)
  924.         if (*npstr)
  925.             SendMessage(hwndList, LB_ADDSTRING, 0,
  926.                 (LONG)(LPSTR)npstr);
  927.     LocalFree((HANDLE)npText);
  928.         
  929.     /* OK to redraw list box now.  Also draw its title */
  930.     SendMessage(hwndList, WM_SETREDRAW, TRUE, 0L);
  931.     InvalidateRect(hwndList, NULL, TRUE);
  932.     SetWindowText(hwndListStatic, szText);
  933.     InvalidateRect(hwndListStatic, NULL, TRUE);
  934.  
  935.     /* Done with hourglass */
  936.     ShowCursor(FALSE);
  937.     SetCursor(hCursor);
  938.  
  939.     return 0L;
  940. }
  941.  
  942.  
  943. /*  WalkFreeList
  944.  *      Walks the free list, putting the result in a list box.
  945.  */
  946.  
  947. LONG WalkFreeList(
  948.     HWND hwnd)
  949. {
  950.     GLOBALINFO GlobalInf;
  951.     GLOBALENTRY Global;
  952.     MODULEENTRY Module;
  953.     char *npText;
  954.     char *npstr;
  955.     int i;
  956.     HCURSOR hCursor;
  957.  
  958.     /* Turn on the hourglass */
  959.     hCursor = SetCursor(LoadCursor(NULL, IDC_WAIT));
  960.     ShowCursor(TRUE);
  961.     wListStatus = LIST_GLOBAL;
  962.  
  963.     /* Allocate a buffer to store this stuff in */
  964.     GlobalInf.dwSize = sizeof (GLOBALINFO);
  965.     GlobalInfo(&GlobalInf);
  966.     npText = npstr = (char *)LocalAlloc(LMEM_FIXED | LMEM_ZEROINIT,
  967.         (GlobalInf.wcItemsFree + 10) * (LIST_WIDTH + 1));
  968.     if (!npText)
  969.         return 0L;
  970.  
  971.     /* Loop through the global heap */
  972.     Global.dwSize = sizeof (GLOBALENTRY);
  973.     if (GlobalFirst(&Global, GLOBAL_FREE))
  974.     {
  975.         i = 0;
  976.         do
  977.         {
  978.             /* Get the module name */
  979.             Module.dwSize = sizeof (MODULEENTRY);
  980.             if (!Global.hOwner)
  981.                 lstrcpy(Module.szModule, "FREE");
  982.             else if (!ModuleFindHandle(&Module, Global.hOwner))
  983.                 *Module.szModule = '\0';
  984.  
  985.             /* Put some fun garbage in the text buffer */
  986.             sprintf(npstr, "A=%08lX h=%04X S=%08lX O=%04X f=%02X T=%2d %c %s",
  987.                 Global.dwAddress, Global.hBlock, Global.dwBlockSize,
  988.                 Global.hOwner, Global.wFlags, Global.wType,
  989.                 Global.wHeapPresent ? 'Y' : 'N', Module.szModule);
  990.  
  991.             /* Bump to the next spot */
  992.             npstr += LIST_WIDTH + 1;
  993.             ++i;
  994.         }
  995.         while (GlobalNext(&Global, GLOBAL_FREE));
  996.     }
  997.  
  998.     /* Create number of items string */
  999.     sprintf(szText, "GLOBAL_FREE:  Items = %u Really = %u",
  1000.         GlobalInf.wcItemsFree, i);
  1001.  
  1002.     /* Clear list box */
  1003.     SendMessage(hwndList, WM_SETREDRAW, FALSE, 0L);
  1004.     SendMessage(hwndList, LB_RESETCONTENT, 0, 0L);
  1005.  
  1006.     /* Loop through all blocks, putting them in list box */
  1007.     for (i = 0, npstr = npText ; i < GlobalInf.wcItemsFree ;
  1008.         ++i, npstr += LIST_WIDTH + 1)
  1009.         if (*npstr)
  1010.             SendMessage(hwndList, LB_ADDSTRING, 0,
  1011.                 (LONG)(LPSTR)npstr);
  1012.     LocalFree((HANDLE)npText);
  1013.         
  1014.     /* OK to redraw list box now.  Also draw its title */
  1015.     SendMessage(hwndList, WM_SETREDRAW, TRUE, 0L);
  1016.     InvalidateRect(hwndList, NULL, TRUE);
  1017.     SetWindowText(hwndListStatic, szText);
  1018.     InvalidateRect(hwndListStatic, NULL, TRUE);
  1019.  
  1020.     /* Done with hourglass */
  1021.     ShowCursor(FALSE);
  1022.     SetCursor(hCursor);
  1023.  
  1024.     return 0L;
  1025. }
  1026.  
  1027.  
  1028. /*  WalkLRUList
  1029.  *      Walks the LRU list, putting the result in a list box.
  1030.  */
  1031.  
  1032. LONG WalkLRUList(
  1033.     HWND hwnd)
  1034. {
  1035.     GLOBALINFO GlobalInf;
  1036.     GLOBALENTRY Global;
  1037.     MODULEENTRY Module;
  1038.     char *npText;
  1039.     char *npstr;
  1040.     int i;
  1041.     HCURSOR hCursor;
  1042.  
  1043.     /* Turn on the hourglass */
  1044.     hCursor = SetCursor(LoadCursor(NULL, IDC_WAIT));
  1045.     ShowCursor(TRUE);
  1046.     wListStatus = LIST_GLOBAL;
  1047.  
  1048.     /* Allocate a buffer to store this stuff in */
  1049.     GlobalInf.dwSize = sizeof (GLOBALINFO);
  1050.     GlobalInfo(&GlobalInf);
  1051.     npText = npstr = (char *)LocalAlloc(LMEM_FIXED | LMEM_ZEROINIT,
  1052.         (GlobalInf.wcItemsLRU + 10) * (LIST_WIDTH + 1));
  1053.     if (!npText)
  1054.         return 0L;
  1055.  
  1056.     /* Loop through the global heap */
  1057.     Global.dwSize = sizeof (GLOBALENTRY);
  1058.     if (GlobalFirst(&Global, GLOBAL_LRU))
  1059.     {
  1060.         i = 0;
  1061.         do
  1062.         {
  1063.             /* Get the module name */
  1064.             Module.dwSize = sizeof (MODULEENTRY);
  1065.             if (!Global.hOwner)
  1066.                 lstrcpy(Module.szModule, "FREE");
  1067.             else if (!ModuleFindHandle(&Module, Global.hOwner))
  1068.                 *Module.szModule = '\0';
  1069.  
  1070.             /* Put some fun garbage in the text buffer */
  1071.             sprintf(npstr, "A=%08lX h=%04X S=%08lX O=%04X f=%02X T=%2d %c %s",
  1072.                 Global.dwAddress, Global.hBlock, Global.dwBlockSize,
  1073.                 Global.hOwner, Global.wFlags, Global.wType,
  1074.                 Global.wHeapPresent ? 'Y' : 'N', Module.szModule);
  1075.  
  1076.             /* Bump to the next spot */
  1077.             npstr += LIST_WIDTH + 1;
  1078.             ++i;
  1079.         }
  1080.         while (GlobalNext(&Global, GLOBAL_LRU));
  1081.     }
  1082.  
  1083.     /* Create number of items string */
  1084.     sprintf(szText, "GLOBAL_LRU:  Items = %u Really = %u",
  1085.         GlobalInf.wcItemsLRU, i);
  1086.  
  1087.     /* Clear list box */
  1088.     SendMessage(hwndList, WM_SETREDRAW, FALSE, 0L);
  1089.     SendMessage(hwndList, LB_RESETCONTENT, 0, 0L);
  1090.  
  1091.     /* Loop through all blocks, putting them in list box */
  1092.     for (i = 0, npstr = npText ; i < GlobalInf.wcItemsLRU ;
  1093.         ++i, npstr += LIST_WIDTH + 1)
  1094.         if (*npstr)
  1095.             SendMessage(hwndList, LB_ADDSTRING, 0,
  1096.                 (LONG)(LPSTR)npstr);
  1097.     LocalFree((HANDLE)npText);
  1098.         
  1099.     /* OK to redraw list box now.  Also draw its title */
  1100.     SendMessage(hwndList, WM_SETREDRAW, TRUE, 0L);
  1101.     InvalidateRect(hwndList, NULL, TRUE);
  1102.     SetWindowText(hwndListStatic, szText);
  1103.     InvalidateRect(hwndListStatic, NULL, TRUE);
  1104.  
  1105.     /* Done with hourglass */
  1106.     ShowCursor(FALSE);
  1107.     SetCursor(hCursor);
  1108.  
  1109.     return 0L;
  1110. }
  1111.  
  1112.  
  1113. /*  WalkLocalHeap
  1114.  *      Walks the local heap into the second list box
  1115.  */
  1116.  
  1117. LONG WalkLocalHeap(
  1118.     HWND hwnd,
  1119.     HANDLE hBlock)
  1120. {
  1121.     LOCALENTRY Local;
  1122.     LOCALINFO LocalInf;
  1123.     char *npText;
  1124.     char *npstr;
  1125.     HCURSOR hCursor;
  1126.     WORD i;
  1127.  
  1128.     /* Turn on the hourglass */
  1129.     hCursor = SetCursor(LoadCursor(NULL, IDC_WAIT));
  1130.     ShowCursor(TRUE);
  1131.  
  1132.     /* Allocate a buffer to do the local heapwalk */
  1133.     LocalInf.dwSize = sizeof (LOCALINFO);
  1134.     LocalInfo(&LocalInf, hBlock);
  1135.     npText = npstr = (char *)LocalAlloc(LMEM_FIXED | LMEM_ZEROINIT,
  1136.         LocalInf.wcItems * (LIST_WIDTH + 1));
  1137.     if (!npText)
  1138.         return 0L;
  1139.  
  1140.     /* Loop through the local heap */
  1141.     Local.dwSize = sizeof (LOCALENTRY);
  1142.     if (LocalFirst(&Local, hBlock))
  1143.     {
  1144.         char temp[30];
  1145.  
  1146.         do
  1147.         {
  1148.             /* Get the type string */
  1149.             if (Local.wFlags & LF_FREE)
  1150.                 strcpy(temp, "Free");
  1151.             else if (Local.wHeapType == GDI_HEAP &&
  1152.                 Local.wType <= LT_GDI_MAX)
  1153.                 strcpy(temp, szGDI[Local.wType]);
  1154.             else if (Local.wHeapType == USER_HEAP &&
  1155.                 Local.wType <= LT_USER_MAX)
  1156.                 strcpy(temp, szUser[Local.wType]);
  1157.             else
  1158.                 strcpy(temp, "Unknown");
  1159.  
  1160.             /* Put some fun garbage in the text buffer */
  1161.             sprintf(npstr, "Ad=%04X h=%04X Sz=%04X %-8s L=%02X %s",
  1162.                 Local.wAddress, Local.hHandle, Local.wSize,
  1163.                 szLocalFlags[Local.wFlags & 7], Local.wcLock, temp);
  1164.  
  1165.             /* Bump to the next spot */
  1166.             npstr += LIST_WIDTH + 1;
  1167.         }
  1168.         while (LocalNext(&Local));
  1169.     }
  1170.  
  1171.     /* Clear list box */
  1172.     SendMessage(hwndListLocal, WM_SETREDRAW, FALSE, 0L);
  1173.     SendMessage(hwndListLocal, LB_RESETCONTENT, 0, 0L);
  1174.  
  1175.     /* Loop through all blocks, putting them in list box */
  1176.     for (i = 0, npstr = npText ; i < LocalInf.wcItems ;
  1177.         ++i, npstr += LIST_WIDTH + 1)
  1178.         if (*npstr)
  1179.             SendMessage(hwndListLocal, LB_ADDSTRING, 0,
  1180.                 (LONG)(LPSTR)npstr);
  1181.     LocalFree((HANDLE)npText);
  1182.         
  1183.     /* OK to redraw list box now */
  1184.     SendMessage(hwndListLocal, WM_SETREDRAW, TRUE, 0L);
  1185.     InvalidateRect(hwndListLocal, NULL, TRUE);
  1186.  
  1187.     /* Done with hourglass */
  1188.     ShowCursor(FALSE);
  1189.     SetCursor(hCursor);
  1190.  
  1191.     return 0L;
  1192. }
  1193.  
  1194.  
  1195.  
  1196. /*  WalkModuleList
  1197.  *      Walks the module list into the list box
  1198.  */
  1199.  
  1200. LONG WalkModuleList(
  1201.     HWND hwnd)
  1202. {
  1203.     MODULEENTRY Module;
  1204.     HCURSOR hCursor;
  1205.  
  1206.     /* Turn on the hourglass */
  1207.     hCursor = SetCursor(LoadCursor(NULL, IDC_WAIT));
  1208.     ShowCursor(TRUE);
  1209.     wListStatus = LIST_MODULE;
  1210.  
  1211.     /* Clear list box */
  1212.     SendMessage(hwndList, WM_SETREDRAW, FALSE, 0L);
  1213.     SendMessage(hwndList, LB_RESETCONTENT, 0, 0L);
  1214.  
  1215.     /* Loop through the module list */
  1216.     Module.dwSize = sizeof (MODULEENTRY);
  1217.     if (ModuleFirst(&Module))
  1218.         do
  1219.         {
  1220.             /* Put some fun garbage in the text buffer */
  1221.             sprintf(szText, "Mod=%s Path=%s", 
  1222.                 Module.szModule, Module.szExePath);
  1223.  
  1224.             /* Put the string in the list box */
  1225.             SendMessage(hwndList, LB_ADDSTRING, 0, (LONG)(LPSTR)szText);
  1226.         }
  1227.         while (ModuleNext(&Module));
  1228.  
  1229.     /* OK to redraw list box now.  Also draw its title */
  1230.     SendMessage(hwndList, WM_SETREDRAW, TRUE, 0L);
  1231.     InvalidateRect(hwndList, NULL, TRUE);
  1232.     SetWindowText(hwndListStatic, "Module List");
  1233.     InvalidateRect(hwndListStatic, NULL, TRUE);
  1234.  
  1235.     /* Done with hourglass */
  1236.     ShowCursor(FALSE);
  1237.     SetCursor(hCursor);
  1238.  
  1239.     return 0L;
  1240. }
  1241.  
  1242.  
  1243.  
  1244. /*  WalkTaskList
  1245.  *      Walks the module list into the list box
  1246.  */
  1247.  
  1248. LONG WalkTaskList(
  1249.     HWND hwnd)
  1250. {
  1251.     TASKENTRY Task;
  1252.     HCURSOR hCursor;
  1253.  
  1254.     /* Turn on the hourglass */
  1255.     hCursor = SetCursor(LoadCursor(NULL, IDC_WAIT));
  1256.     ShowCursor(TRUE);
  1257.     wListStatus = LIST_TASK;
  1258.  
  1259.     /* Clear list box */
  1260.     SendMessage(hwndList, WM_SETREDRAW, FALSE, 0L);
  1261.     SendMessage(hwndList, LB_RESETCONTENT, 0, 0L);
  1262.  
  1263.     /* Loop through the task list */
  1264.     Task.dwSize = sizeof (TASKENTRY);
  1265.     if (TaskFirst(&Task))
  1266.         do
  1267.         {
  1268.             /* Put some fun garbage in the text buffer */
  1269.             sprintf(szText,
  1270.                 "hTask=%04X Par=%04X hInst=%04X Mod=%04X szMod=%s",
  1271.                 Task.hTask, Task.hTaskParent, Task.hInst, Task.hModule,
  1272.                 Task.szModule);
  1273.  
  1274.             /* Put the string in the list box */
  1275.             SendMessage(hwndList, LB_ADDSTRING, 0, (LONG)(LPSTR)szText);
  1276.         }
  1277.         while (TaskNext(&Task));
  1278.  
  1279.     /* OK to redraw list box now.  Also draw its title */
  1280.     SendMessage(hwndList, WM_SETREDRAW, TRUE, 0L);
  1281.     InvalidateRect(hwndList, NULL, TRUE);
  1282.     SetWindowText(hwndListStatic, "Task List");
  1283.     InvalidateRect(hwndListStatic, NULL, TRUE);
  1284.  
  1285.     /* Done with hourglass */
  1286.     ShowCursor(FALSE);
  1287.     SetCursor(hCursor);
  1288.  
  1289.     return 0L;
  1290. }
  1291.  
  1292.  
  1293.  
  1294. /*  WalkClassList
  1295.  *      Walks the module list into the list box
  1296.  */
  1297.  
  1298. LONG WalkClassList(
  1299.     HWND hwnd)
  1300. {
  1301.     CLASSENTRY Class;
  1302.     HCURSOR hCursor;
  1303.     char szTemp[80];
  1304.  
  1305.     /* Turn on the hourglass */
  1306.     hCursor = SetCursor(LoadCursor(NULL, IDC_WAIT));
  1307.     ShowCursor(TRUE);
  1308.     wListStatus = LIST_CLASS;
  1309.  
  1310.     /* Clear list box */
  1311.     SendMessage(hwndList, WM_SETREDRAW, FALSE, 0L);
  1312.     SendMessage(hwndList, LB_RESETCONTENT, 0, 0L);
  1313.  
  1314.     /* Loop through the class list */
  1315.     Class.dwSize = sizeof (CLASSENTRY);
  1316.     if (ClassFirst(&Class))
  1317.         do
  1318.         {
  1319.             /* Put some fun garbage in the text buffer */
  1320.             sprintf(szText, "Name = %s  hInst = %04X",
  1321.                 Class.szClassName, Class.hInst);
  1322.  
  1323.             /* Put the string in the list box */
  1324.             SendMessage(hwndList, LB_ADDSTRING, 0, (LONG)(LPSTR)szText);
  1325.         }
  1326.         while (ClassNext(&Class));
  1327.  
  1328.     /* OK to redraw list box now.  Also draw its title */
  1329.     SendMessage(hwndList, WM_SETREDRAW, TRUE, 0L);
  1330.     InvalidateRect(hwndList, NULL, TRUE);
  1331.     SetWindowText(hwndListStatic, "Class List");
  1332.     InvalidateRect(hwndListStatic, NULL, TRUE);
  1333.  
  1334.     /* Done with hourglass */
  1335.     ShowCursor(FALSE);
  1336.     SetCursor(hCursor);
  1337.  
  1338.     return 0L;
  1339. }
  1340.  
  1341.  
  1342.  
  1343. /*  DoStackTrace
  1344.  *      Does a stack trace for the current module in the lower box
  1345.  */
  1346.  
  1347. LONG DoStackTrace(
  1348.     HWND hwnd)
  1349. {
  1350.     STACKTRACEENTRY StackTrace;
  1351.     MODULEENTRY ModuleEntry;
  1352.     HCURSOR hCursor;
  1353.     HANDLE hTask;
  1354.     WORD wCS;
  1355.     HANDLE hModule;
  1356.  
  1357.     /* Turn on the hourglass */
  1358.     hCursor = SetCursor(LoadCursor(NULL, IDC_WAIT));
  1359.     ShowCursor(TRUE);
  1360.  
  1361.     /* Get the task handle from the list box */
  1362.     SendMessage(hwndList, LB_GETTEXT,
  1363.         (WORD)SendMessage(hwndList, LB_GETCURSEL, 0, 0L),
  1364.         (LONG)(LPSTR)szText);
  1365.     sscanf(szText, "%*6c%x", &hTask);
  1366.  
  1367.     /* Clear list box */
  1368.     SendMessage(hwndListLocal, WM_SETREDRAW, FALSE, 0L);
  1369.     SendMessage(hwndListLocal, LB_RESETCONTENT, 0, 0L);
  1370.  
  1371.     /* Do the stack trace */
  1372.     StackTrace.dwSize = sizeof (STACKTRACEENTRY);
  1373.     wCS = 0;
  1374.     hModule = NULL;
  1375.     if (StackTraceFirst(&StackTrace, hTask))
  1376.         do
  1377.         {
  1378.             /* Get the module name */
  1379.             ModuleEntry.dwSize = sizeof (MODULEENTRY);
  1380.             if (!ModuleFindHandle(&ModuleEntry, StackTrace.hModule))
  1381.                 ModuleEntry.szModule[0] = '\0';
  1382.  
  1383.             /* Put some fun garbage in the text buffer */
  1384.             sprintf(szText, "BP=%04X CS:IP=%04X:%04X (Mod=%s Seg=%u)", 
  1385.                 StackTrace.wBP, StackTrace.wCS, StackTrace.wIP,
  1386.                 ModuleEntry.szModule, StackTrace.wSegment);
  1387.  
  1388.             /* Set the last wCS in case we're using a near frame */
  1389.             if (StackTrace.wCS)
  1390.             {
  1391.                 wCS = StackTrace.wCS;
  1392.                 hModule = StackTrace.hModule;
  1393.             }
  1394.  
  1395.             /* Put the string in the list box */
  1396.             SendMessage(hwndListLocal, LB_ADDSTRING, 0, (LONG)(LPSTR)szText);
  1397.         }
  1398.         while (StackTraceNext(&StackTrace));
  1399.  
  1400.     /* OK to redraw list box now */
  1401.     SendMessage(hwndListLocal, WM_SETREDRAW, TRUE, 0L);
  1402.     InvalidateRect(hwndListLocal, NULL, TRUE);
  1403.  
  1404.     /* Done with hourglass */
  1405.     ShowCursor(FALSE);
  1406.     SetCursor(hCursor);
  1407.  
  1408.     return 0L;
  1409. }
  1410.  
  1411.  
  1412. /*  DoUserInfo
  1413.  *      Displays the data from a call to UserInfo()
  1414.  */
  1415.  
  1416. LONG DoUserInfo(
  1417.     HWND hwnd)
  1418. {
  1419.     USERHEAPINFO User;
  1420.  
  1421.     wListStatus = LIST_USER;
  1422.  
  1423.     /* Clear list box */
  1424.     SendMessage(hwndList, WM_SETREDRAW, FALSE, 0L);
  1425.     SendMessage(hwndList, LB_RESETCONTENT, 0, 0L);
  1426.  
  1427.     /* Get the user information */
  1428.     User.dwSize = sizeof (USERHEAPINFO);
  1429.     UserHeapInfo(&User);
  1430.  
  1431.     /* Display the User information */
  1432.     wsprintf(szText, "hSegment = %04X", User.hSegment);
  1433.     SendMessage(hwndList, LB_ADDSTRING, 0, (LONG)(LPSTR)szText);
  1434.     wsprintf(szText, "wHeapFree = %u", User.wHeapFree);
  1435.     SendMessage(hwndList, LB_ADDSTRING, 0, (LONG)(LPSTR)szText);
  1436.     wsprintf(szText, "wMaxHeapSize = %u", User.wMaxHeapSize);
  1437.     SendMessage(hwndList, LB_ADDSTRING, 0, (LONG)(LPSTR)szText);
  1438.     wsprintf(szText, "User Free = %u%%", User.wPercentFree);
  1439.     SendMessage(hwndList, LB_ADDSTRING, 0, (LONG)(LPSTR)szText);
  1440.  
  1441.     /* OK to redraw list box now.  Also draw its title */
  1442.     SendMessage(hwndList, WM_SETREDRAW, TRUE, 0L);
  1443.     InvalidateRect(hwndList, NULL, TRUE);
  1444.     SetWindowText(hwndListStatic, "User Information");
  1445.     InvalidateRect(hwndListStatic, NULL, TRUE);
  1446.  
  1447.     return 0L;
  1448. }
  1449.  
  1450.  
  1451. /*  DoGDIInfo
  1452.  *      Displays the data from a call to UserInfo()
  1453.  */
  1454.  
  1455. LONG DoGDIInfo(
  1456.     HWND hwnd)
  1457. {
  1458.     GDIHEAPINFO GDI;
  1459.  
  1460.     wListStatus = LIST_GDI;
  1461.  
  1462.     /* Clear list box */
  1463.     SendMessage(hwndList, WM_SETREDRAW, FALSE, 0L);
  1464.     SendMessage(hwndList, LB_RESETCONTENT, 0, 0L);
  1465.  
  1466.     /* Get the GDI information */
  1467.     GDI.dwSize = sizeof (GDIHEAPINFO);
  1468.     GDIHeapInfo(&GDI);
  1469.  
  1470.     /* Display the GDI information */
  1471.     wsprintf(szText, "hSegment = %04X", GDI.hSegment);
  1472.     SendMessage(hwndList, LB_ADDSTRING, 0, (LONG)(LPSTR)szText);
  1473.     wsprintf(szText, "wHeapFree = %u", GDI.wHeapFree);
  1474.     SendMessage(hwndList, LB_ADDSTRING, 0, (LONG)(LPSTR)szText);
  1475.     wsprintf(szText, "wMaxHeapSize = %u", GDI.wMaxHeapSize);
  1476.     SendMessage(hwndList, LB_ADDSTRING, 0, (LONG)(LPSTR)szText);
  1477.     wsprintf(szText, "GDI Free = %u%%", GDI.wPercentFree);
  1478.     SendMessage(hwndList, LB_ADDSTRING, 0, (LONG)(LPSTR)szText);
  1479.  
  1480.     /* OK to redraw list box now.  Also draw its title */
  1481.     SendMessage(hwndList, WM_SETREDRAW, TRUE, 0L);
  1482.     InvalidateRect(hwndList, NULL, TRUE);
  1483.     SetWindowText(hwndListStatic, "GDI Information");
  1484.     InvalidateRect(hwndListStatic, NULL, TRUE);
  1485.  
  1486.     return 0L;
  1487. }
  1488.  
  1489.  
  1490. /*  DoMemManInfo
  1491.  *      Displays the data from a call to UserInfo()
  1492.  */
  1493.  
  1494. LONG DoMemManInfo(
  1495.     HWND hwnd)
  1496. {
  1497.     MEMMANINFO MemMan;
  1498.  
  1499.     wListStatus = LIST_MEMMAN;
  1500.  
  1501.     /* Clear list box */
  1502.     SendMessage(hwndList, WM_SETREDRAW, FALSE, 0L);
  1503.     SendMessage(hwndList, LB_RESETCONTENT, 0, 0L);
  1504.  
  1505.     /* Get the Memory manager information */
  1506.     MemMan.dwSize = sizeof (MEMMANINFO);
  1507.     MemManInfo(&MemMan);
  1508.  
  1509.     /* Display the MemMan information */
  1510.     wsprintf(szText, "Largest Free Block = %08lXh", MemMan.dwLargestFreeBlock);
  1511.     SendMessage(hwndList, LB_ADDSTRING, 0, (LONG)(LPSTR)szText);
  1512.     wsprintf(szText, "Max Pages Available = %08lXh", MemMan.dwMaxPagesAvailable);
  1513.     SendMessage(hwndList, LB_ADDSTRING, 0, (LONG)(LPSTR)szText);
  1514.     wsprintf(szText, "Max Pages Lockable = %08lXh", MemMan.dwMaxPagesLockable);
  1515.     SendMessage(hwndList, LB_ADDSTRING, 0, (LONG)(LPSTR)szText);
  1516.     wsprintf(szText, "Total Linear Space = %08lXh", MemMan.dwTotalLinearSpace);
  1517.     SendMessage(hwndList, LB_ADDSTRING, 0, (LONG)(LPSTR)szText);
  1518.     wsprintf(szText, "Total Unlocked Pages = %08lXh", MemMan.dwTotalUnlockedPages);
  1519.     SendMessage(hwndList, LB_ADDSTRING, 0, (LONG)(LPSTR)szText);
  1520.     wsprintf(szText, "Free Pages = %08lXh", MemMan.dwFreePages);
  1521.     SendMessage(hwndList, LB_ADDSTRING, 0, (LONG)(LPSTR)szText);
  1522.     wsprintf(szText, "Total Pages = %08lXh", MemMan.dwTotalPages);
  1523.     SendMessage(hwndList, LB_ADDSTRING, 0, (LONG)(LPSTR)szText);
  1524.     wsprintf(szText, "Free Linear Space = %08lXh", MemMan.dwFreeLinearSpace);
  1525.     SendMessage(hwndList, LB_ADDSTRING, 0, (LONG)(LPSTR)szText);
  1526.     wsprintf(szText, "Swap File Pages = %08lXh", MemMan.dwSwapFilePages);
  1527.     SendMessage(hwndList, LB_ADDSTRING, 0, (LONG)(LPSTR)szText);
  1528.     wsprintf(szText, "Page Size = %04Xh", MemMan.wPageSize);
  1529.     SendMessage(hwndList, LB_ADDSTRING, 0, (LONG)(LPSTR)szText);
  1530.  
  1531.     /* OK to redraw list box now.  Also draw its title */
  1532.     SendMessage(hwndList, WM_SETREDRAW, TRUE, 0L);
  1533.     InvalidateRect(hwndList, NULL, TRUE);
  1534.     SetWindowText(hwndListStatic, "Memory Manager Information");
  1535.     InvalidateRect(hwndListStatic, NULL, TRUE);
  1536.  
  1537.     return 0L;
  1538. }
  1539.  
  1540. /*  DoGlobalEntryModuleTest
  1541.  *      Tests the GlobalEntryModule API for correctness.
  1542.  */
  1543.  
  1544. LONG DoGlobalEntryModuleTest(
  1545.     HWND hwnd)
  1546. {
  1547.     GLOBALENTRY Global;
  1548.     HANDLE hModule;
  1549.  
  1550.     /* Get an interesting module handle */
  1551.     hModule = GetModuleHandle("USER");
  1552.  
  1553.     /* Find out about the segment */
  1554.     Global.dwSize = sizeof (GLOBALENTRY);
  1555.     if (!GlobalEntryModule(&Global, hModule, 14))
  1556.         MessageBox(hwnd, "Error returned!", "GlobalEntryModule Test",
  1557.             MB_OK | MB_ICONEXCLAMATION);
  1558.     else
  1559.     {
  1560.         wsprintf(szText, "USER Code Seg 14 has handle %04X", Global.hBlock);
  1561.         MessageBox(hwnd, szText, "GlobalEntryModule Test",
  1562.             MB_OK | MB_ICONINFORMATION);
  1563.     }
  1564. }
  1565.  
  1566.  
  1567. /*  ReadMemoryTest
  1568.  *      Opens a popup window and allows the user to scroll through the
  1569.  *      contents of the memory block.
  1570.  */
  1571.  
  1572. LONG ReadMemoryTest(
  1573.     HWND hwnd,
  1574.     HANDLE hBlock)
  1575. {
  1576.     HWND hwndPopup;
  1577.     GLOBALENTRY Global;
  1578.  
  1579.     /* Make a popup window to handle the data */
  1580.     Global.dwSize = sizeof (GLOBALENTRY);
  1581.     GlobalEntryHandle(&Global, hBlock);
  1582.     wsprintf(szText,"Handle = %4Xh  Length = %8lXh",
  1583.         hBlock, Global.dwBlockSize);
  1584.     hwndPopup = CreateWindow(
  1585.         szMemName,
  1586.         szText,
  1587.         WS_POPUP | WS_CAPTION |
  1588.         WS_SYSMENU | WS_THICKFRAME | WS_MAXIMIZEBOX | WS_VSCROLL,
  1589.         xScreen / 2 - 45 * xChar,
  1590.         yScreen / 8,
  1591.         90 * xChar,
  1592.         2 * yScreen / 3,
  1593.         hwnd,
  1594.         NULL,
  1595.         hInst,
  1596.         (LPSTR)MAKELONG(hBlock, 0));
  1597.  
  1598.     /* Display the window */
  1599.     ShowWindow(hwndPopup, SW_SHOWNORMAL);
  1600.     UpdateWindow(hwndPopup);
  1601.  
  1602.     return 0L;
  1603. }
  1604.  
  1605.  
  1606. /*  TimerCountTest
  1607.  *      Tests the timer count function.
  1608.  */
  1609.  
  1610. LONG TimerCountTest(
  1611.     HWND hwnd)
  1612. {
  1613.     TIMERINFO TimerInfo;
  1614.  
  1615.     /* Get the tick count */
  1616.     TimerInfo.dwSize = sizeof (TIMERINFO);
  1617.     if (!TimerCount(&TimerInfo))
  1618.     {
  1619.         MessageBox(hwnd, "Error calling TimerCount()", "Timer Count Test",
  1620.             MB_OK);
  1621.         return 0L;
  1622.     }
  1623.  
  1624.     /* Display it */
  1625.     wsprintf(szText, "Milliseconds since Windows started = %ld\r\n"
  1626.         "Milliseconds in this VM = %ld",
  1627.         TimerInfo.dwmsSinceStart, TimerInfo.dwmsThisVM);
  1628.     MessageBox(hwnd, szText, "Timer Count Test", MB_OK | MB_ICONINFORMATION);
  1629.  
  1630.     /* Return success */
  1631.     return 0L;
  1632. }
  1633.  
  1634.  
  1635. /*  MyNotifyHandler
  1636.  *      Notification message callback
  1637.  */
  1638.  
  1639. BOOL FAR PASCAL MyNotifyHandler(
  1640.     WORD wID,
  1641.     DWORD dwData)
  1642. {
  1643.     /* See if we should process this notification */
  1644.     if (!wNotifyState)
  1645.         return FALSE;
  1646.  
  1647.     /* Filter out task switch notifications if necessary */
  1648.     if (wFilterState && (wID == NFY_TASKIN || wID == NFY_TASKOUT))
  1649.         return FALSE;
  1650.  
  1651.     /* Put the information in a message */
  1652.     PostMessage(hwndMain, WM_USER, wID, dwData);
  1653.  
  1654.     /* Only return that we handled debug strings and RIPs */
  1655.     if (wID == NFY_RIP || wID == NFY_DEBUGSTR)
  1656.         return TRUE;
  1657.     else
  1658.         return FALSE;
  1659. }
  1660.  
  1661.  
  1662. /*  MyCFaultHandler
  1663.  *      This routine is used to prove that C routines can be used to
  1664.  *      make fault handlers.  As can be seen here, the parameters are
  1665.  *      actually pointing into the stack frame.  Two important notes:
  1666.  *          1) This function MUST be declared as _cdecl so that the
  1667.  *              parameters are not popped off the stack!
  1668.  *          2) This function may change these values with the understanding
  1669.  *              that they are actually passed "by value" implying that
  1670.  *              any changes are for real.
  1671.  *      As defined in MyFaultHandler (TEST2.ASM), 0 nukes app, 1 restarts
  1672.  *      the instruction, 2 chains on.
  1673.  */
  1674.  
  1675. WORD _cdecl MyCFaultHandler(
  1676.     WORD wES,
  1677.     WORD wDS,
  1678.     WORD wDI,
  1679.     WORD wSI,
  1680.     WORD wBP,
  1681.     WORD wSP,
  1682.     WORD wBX,
  1683.     WORD wDX,
  1684.     WORD wCX,
  1685.     WORD wOldAX,
  1686.     WORD wOldBP,
  1687.     WORD wRetIP,
  1688.     WORD wRetCS,
  1689.     WORD wRealAX,
  1690.     WORD wNumber,
  1691.     WORD wHandle,
  1692.     WORD wIP,
  1693.     WORD wCS,
  1694.     WORD wFlags)
  1695. {
  1696.     FARPROC lpfnDlg;
  1697.     int nResult;
  1698.     static WORD wReentry;
  1699.  
  1700.     /* See if we're already here.  If so, tell routine to chain on */
  1701.     if (wReentry)
  1702.         return 2;
  1703.     wReentry = 1;
  1704.  
  1705.     /* If this was a CtlAltSysRq interrupt, just restart the instr. */
  1706.     if (wNumber == INT_CTLALTSYSRQ)
  1707.     {
  1708.         wsprintf(szText, "THTest:  CtlAltSysRq at %04X:%04X\r\n", wCS, wIP);
  1709.         OutputDebugString(szText);
  1710.         wReentry = 0;
  1711.         return 1;
  1712.     }
  1713.  
  1714.     /* Set the static variables */
  1715.     wsCS = wCS;
  1716.     wsIP = wIP;
  1717.     wsFault = wNumber;
  1718.     wsFaultTask = GetCurrentTask();
  1719.  
  1720.     /* Use the dialog box to determine what to do with the fault */
  1721.     lpfnDlg = MakeProcInstance((FARPROC)FaultDialogProc, hInst);
  1722.     nResult = DialogBox(hInst, MAKEINTRESOURCE(IDD_FAULT), hwndMain, lpfnDlg);
  1723.     FreeProcInstance(lpfnDlg);
  1724.  
  1725.     /* We're getting out now, so undo reentry flag */
  1726.     wReentry = 0;
  1727.  
  1728.     return (WORD)nResult;
  1729. }
  1730.  
  1731.  
  1732. /*  FaultDialogProc
  1733.  *      Handles the Fault dialog box
  1734.  *      It returns 0 to nuke the app, 1 to restart the instruction,
  1735.  *      2 to chain on
  1736.  */
  1737.  
  1738. BOOL FAR PASCAL FaultDialogProc(
  1739.     HWND hDlg,
  1740.     WORD wMessage,
  1741.     WORD wParam,
  1742.     DWORD dwParam)
  1743. {
  1744.     switch (wMessage)
  1745.     {
  1746.     case WM_INITDIALOG:
  1747.         wsprintf(szText, "%d", wsFault);
  1748.         SetDlgItemText(hDlg, IDC_FAULTNUM, szText);
  1749.         wsprintf(szText, "%04X:%04X", wsCS, wsIP);
  1750.         SetDlgItemText(hDlg, IDC_CSIP, szText);
  1751.         wsprintf(szText, "%04X", wsFaultTask);
  1752.         SetDlgItemText(hDlg, IDC_HFAULT, szText);
  1753.         wsprintf(szText, "%04X", wsProgramTask);
  1754.         SetDlgItemText(hDlg, IDC_HPROGRAM, szText);
  1755.         return TRUE;
  1756.  
  1757.     case WM_COMMAND:
  1758.         switch (wParam)
  1759.         {
  1760.         case IDC_KILL:
  1761.             EndDialog(hDlg, 0);
  1762.             return TRUE;
  1763.  
  1764.         case IDC_RESTART:
  1765.             EndDialog(hDlg, 1);
  1766.             return TRUE;
  1767.  
  1768.         case IDC_CHAIN:
  1769.             EndDialog(hDlg, 2);
  1770.             return TRUE;
  1771.  
  1772.         default:
  1773.             return FALSE;
  1774.         }
  1775.  
  1776.     default:
  1777.         return FALSE;
  1778.     }
  1779. }
  1780.